package com.ms.orm.mapper;

import com.ms.orm.annotation.DbType;
import com.ms.orm.annotation.Param;
import com.ms.orm.constants.StringPool;
import com.ms.orm.context.DefaultLittleOrmContext;
import com.ms.orm.meta.IPage;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;

/**
 * @author .
 */
public class DynamicSqlRepository{

    /**
     * Map<String, Map<String, SqlParser.SqlStatement>>
     * key = Mapper 全限定名，比如 com.ms.example.UserMapper
     * value = Mapper
     *
     *      Map<String, SqlParser.SqlStatement>
     *            key = Mapper中的方法，，比如 com.ms.example.UserMapper.selectUsersWithConditions
     *            value = 方法对应的sql、sql中的条件参数占位符作为key,条件内部内容作为值
     *
     *     sql:
     *          SELECT u.id, u.name, u.age, d.department_name
     *          FROM user u
     *          LEFT JOIN departments d ON u.department_id = d.id
     *          WHERE 1=1
     *
     *              ${name != null && name != "" } 或者 ${name != null || name != "" } 或者 或者 ${name != "" } 或者 ${name != "2" } 或者 ${name == "op" }
     *              ${age != null}
     *
     *
     */
    private final Map<String, Map<String, SqlParser.SqlStatement>> sqlStatementsByMapper;
    public Map<String, Map<String, SqlParser.SqlStatement>> getSqlStatementsByMapper() {
        return sqlStatementsByMapper;
    }

    public DynamicSqlRepository() throws Exception {
        this.sqlStatementsByMapper = SqlParser.parseSqlFiles();
    }


    public String buildFinalSql(SqlParser.SqlStatement sqlStatement, Map<String, Object> params) {
        StringBuilder sqlBuilder = new StringBuilder(sqlStatement.getBaseSql());

        for (Map.Entry<String, String> entry : sqlStatement.getConditions().entrySet()) {

            String conditionKey = "${" + entry.getKey() + "}";
            String conditionValue = entry.getValue();

            boolean shouldInclude = ExpressionEvaluator.evaluateExpression(entry.getKey(),params);
            if (shouldInclude) {
                sqlBuilder = new StringBuilder(sqlBuilder.toString().replace(conditionKey, conditionValue));
            } else {
                sqlBuilder = new StringBuilder(sqlBuilder.toString().replace(conditionKey, ""));
            }
        }
        // Normalize whitespace
        return sqlBuilder.toString().replaceAll("\\s+", " ").trim();
    }

    /**
     * 分页时候的总数，过滤分页属性
     * @param sqlStatement
     * @param params
     * @return
     */
    public String buildFinalSqlForCount(SqlParser.SqlStatement sqlStatement, Map<String, Object> params) {
        StringBuilder sqlBuilder = new StringBuilder(sqlStatement.getBaseSql());

        for (Map.Entry<String, String> entry : sqlStatement.getConditions().entrySet()) {
            String conditionKey = "${" + entry.getKey() + "}";
            String conditionValue = entry.getValue();

            //过滤分页属性
            if((entry.getKey().contains(StringPool.LIMIT_U) || entry.getKey().contains(StringPool.LIMIT_L))){
                sqlBuilder = new StringBuilder(sqlBuilder.toString().replace(conditionKey, ""));
                continue;
            }
            if((entry.getKey().contains(StringPool.OFFSET_U) || entry.getKey().contains(StringPool.OFFSET_L))){
                sqlBuilder = new StringBuilder(sqlBuilder.toString().replace(conditionKey, ""));
                continue;
            }

            boolean shouldInclude = ExpressionEvaluator.evaluateExpression(entry.getKey(),params);
            if (shouldInclude) {
                sqlBuilder = new StringBuilder(sqlBuilder.toString().replace(conditionKey, conditionValue));
            } else {
                sqlBuilder = new StringBuilder(sqlBuilder.toString().replace(conditionKey, ""));
            }
        }
        return new StringBuilder("select count(*) from (").append(sqlBuilder.toString().replaceAll("\\s+", " ").trim()).append(") a").toString();
    }

    @Deprecated
    private boolean evaluateCondition(String conditionExpression, Map<String, Object> params) {
        // Implement a simple expression evaluator or use an existing library like MVEL or SpEL.
        // Here we will just check if the parameter exists and is not null as a placeholder.
        return params.containsKey(conditionExpression) && params.get(conditionExpression) != null;
    }

    public Map<String, Object> extractParams(Object[] args, Annotation[][] paramAnnotations) {
        Map<String, Object> params = new HashMap<>();
        params.clear();
        for (int i = 0; i < args.length; i++) {
            Param paramAnnotation = findAnnotation(paramAnnotations[i], Param.class);
            if (paramAnnotation != null) {
                if(args[i] instanceof Map) {
                    params.putAll((Map) args[i]);
                }else if(args[i] instanceof IPage){
                    //提取分页参数
                    IPage page = ((IPage) args[i]);
                    params.put("page",page);
                    if(DefaultLittleOrmContext.dbType==null || DefaultLittleOrmContext.dbType.equals(DbType.MYSQL)) {
                        params.put("limit", page.getSize());
                        params.put("LIMIT", page.getSize());
                        params.put("offset", page.offset());
                        params.put("OFFSET", page.offset());
                    }else if(DefaultLittleOrmContext.dbType!=null && DefaultLittleOrmContext.dbType.equals(DbType.ORACLE)){
                        //upperLimit(最大行号数): page * pageSize + pageSize
                        /*params.put("upperLimit", page.getCurrent()*page.getSize()+page.getSize());
                        //这里是  lowerLimit(最小行号数): 应该设置为 page * pageSize + 1
                        params.put("lowerLimit", page.offset());
                        params.put("UPPERLIMIT",  page.getCurrent()*page.getSize()+page.getSize());
                        params.put("LOWERLIMIT", page.offset());*/
                        //为了通一
                        params.put("limit", page.getCurrent()*page.getSize()+page.getSize());
                        params.put("LIMIT", params.get("limit"));
                        params.put("offset", page.offset());
                        params.put("OFFSET", page.offset());
                    }else {

                    }
                }else{
                    params.put(paramAnnotation.value(), args[i]);
                }
            }
        }
        return params;
    }

    /**
     * 分页查询总数
     * @param args
     * @param paramAnnotations
     * @return
     */
    public Map<String, Object> extractParamsForCount(Object[] args, Annotation[][] paramAnnotations) {
        Map<String, Object> params = new HashMap<>();
        for (int i = 0; i < args.length; i++) {
            Param paramAnnotation = findAnnotation(paramAnnotations[i], Param.class);
            if (paramAnnotation != null) {
                if(args[i] instanceof Map){
                    params.putAll((Map)args[i]);
                }else{
                    params.put(paramAnnotation.value(), args[i]);
                }
            }
        }
        return params;
    }

    public <T extends Annotation> T findAnnotation(Annotation[] annotations, Class<T> annotationClass) {
        for (Annotation annotation : annotations) {
            if (annotation.annotationType().equals(annotationClass)) {
                return (T) annotation;
            }
        }
        return null;
    }

}
